package org.fpp.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoop;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.ReflectiveChannelFactory;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.resolver.dns.DnsAddressResolverGroup;
import io.netty.resolver.dns.DnsNameResolverBuilder;
import io.netty.resolver.dns.DnsServerAddressStreamProvider;
import io.netty.resolver.dns.SingletonDnsServerAddressStreamProvider;

import java.net.InetSocketAddress;
import java.util.concurrent.Executors;

import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.SECONDS;

/**
 * @author bigbird-0101
 * @date 2025-03-16 23:33
 */
public class NettyClient {
    private Channel channel;
    private Bootstrap bootstrap;

    public NettyClient(InetSocketAddress address) {
        init(address);
    }

    public void init(InetSocketAddress address) {
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.remoteAddress(address);
        EventLoopGroup group = new NioEventLoopGroup();
        DnsServerAddressStreamProvider provider = new SingletonDnsServerAddressStreamProvider(
                new InetSocketAddress("192.168.1.106", 53));
        EventLoop next = group.next();
        DnsAddressResolverGroup resolverGroup = new DnsAddressResolverGroup(
                new DnsNameResolverBuilder(next)
                        .queryTimeoutMillis(15000)
                        .channelFactory(new ReflectiveChannelFactory<>(NioDatagramChannel.class))
                        .nameServerProvider(provider)
        );
        bootstrap.resolver(resolverGroup);
        bootstrap.channel(NioSocketChannel.class);
        bootstrap.group(new NioEventLoopGroup());
        bootstrap.option(ChannelOption.SO_KEEPALIVE, true)
                .option(ChannelOption.TCP_NODELAY, true)
                .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
        bootstrap.handler(new ChannelInitializer<SocketChannel>() {

            @Override
            protected void initChannel(SocketChannel ch) {
                ch.pipeline().addFirst(new StringEncoder(), new StringDecoder(),new NettyConnectionHandler());
            }
        });
        this.bootstrap = bootstrap;
        doConnection(bootstrap);
        Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> {
            if (null==channel ||!channel.isOpen()) {
                System.out.println("开启重连");
                disConnection();
                System.out.println("重连成功");
            }
        }, 0, 5, SECONDS);
    }

    public void doConnection(Bootstrap bootstrap) {
        ChannelFuture connect = bootstrap.connect();
        boolean ret = connect.awaitUninterruptibly(2000, MILLISECONDS);
        if(ret) {
            this.channel = connect.channel();
            System.out.println(this.channel);
        }
    }

    public void disConnection() {
        if (channel != null && channel.isOpen()) {
            channel.close();
        }
        doConnection(bootstrap);
    }

    public void sendMsg(String msg) {
        if (channel != null && channel.isOpen()) {
            System.out.println("12312312");
            channel.writeAndFlush(msg);
        }
    }

    public static void main(String[] args) {
        NettyClient client = new NettyClient(new InetSocketAddress("8888.iot.com", 8888));
        while (true) {
            try {
                client.sendMsg("hello world");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class NettyConnectionHandler extends ChannelInboundHandlerAdapter{
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        ctx.channel().close();
    }
}